//
// Created by wxd on 2025/8/25.
// 提供一个全局的线程安全，高性能的id生成器，用于对象traceId的生成，便于后面针对渲染引擎框架的问题排查
//
/**
 * 全局线程安全，高性能的id生成器的设计思路
 * 在设计之前，我们先了解一下C++中的多线程编程相关的对象
 * 1. thread_local: 每个线程都有该变量的独立副本， 线程第一次访问时初始化，线程结束时自动销毁，避免了多线程间的数据竞争
 *    最佳实践：static thread_local std::unique_ptr<T> instance, 这里的静态表示同一个线程内多次访问时，返回的是同一个实例
 *    由于每个线程是自己维护各自的对象，所以无需通过锁机制来实现并发安全，减少锁机制带来的性能开销
 *
 * 2. std::atomic<T>: C++中提供的基于CAS无锁机制的原子类
 *    2.1 原子赋值操作
 *        std::atomic<int> counter(0);
 *        std::atomic<int> counter = 0;
 *        counter.store(0, std::memory_order_relaxed)
 *    2.2 原子获取操作
 *        int cur_val = counter.load(std::memory_order_relaxed)
 *
 *    2.3 原子操作
 *        int old_val = counter.fetch_add(1, std::memory_order_relaxed)
 *        counter原子自增+1，然后返回自增之前的counter
 *
 *        fetch_sub; fetch_[and, or, xor]等操作
 *
 *    2.4 cas比较
 *        counter.compare_exchange_strong(expected, updateValue)
 *        counter.compare_exchange_weak(expected, updateValue): 性能更好，但是存在失败，如果对一致性不高的场景，可以使用weak-cas
 *
 * 3. std::mutex: C++标准库提供的互斥锁，用于保护共享数据免受多线程同时访问
 *    创建锁: std::mutex mtx;
 *    基本用法：
 *      mtx.lock()
 *      TODO：代码临界区
 *      mtx.unlock()
 *    推荐用法: std::lock_guard, 自动管理所(RAII)
 *       std::lock_guard<std::mutex> lock(mtx)
 *    更加灵活的锁机制：std::unique_lock
 *       std::unique_lock<std::mutex> lock(mtx);
 *    尝试锁：mtx.try_lock, 非阻塞式
 */

/**
 * 自增ID设计
 * 1. 自增ID是全局的，所以我们采用单例模式，但是由于每个线程独有一个ID自增器（避免通过锁机制保证多线程下的ID自增的线程安全问题）
 *    我们最终采取的整体结构：单例 + 线程局部存储
 *    IDGenerator：ID自增器，单例，内部维护一个原子ID自增对象AtomicIDGenerator(私有)
 *
 * 2. ID的结构设计，这里我们采用64位ID, 其中ID结构： 时间戳 (42位) | 实例ID(10位) | 序列号(12位)
 *
 * 3. ID前缀：用于区分不同组件场景或者业务场景，暂时仅区分渲染引擎组件场景，这里可以通过枚举类来实现
 *
 * 4. ID统计监控系统：监控ID生成性能和使用情况
 *
 * 5. TraceScope - RAII追踪器：自动追踪函数执行时间和生命周期
 *
 * 自增ID的API设计
 *  AtomicIDGenerator：原子生成器
 *   1. generate(): 生成64位的TraceID （ID生成的核心算法）
 *
 *  IDGenerator：单例ID自增器
 *   1. generateRaw(): 生成原始的TraceID，这里的id实际不会与组件或者业务耦合，单纯的生成TraceID
 *   2. generateString(prefix): 生成带有前缀的TraceID，这里会结合组件或者业务场景来生成对应的TraceID
 *   3. generateCustomString(prefix): 生成自定义前缀的TraceID，用于扩展，2中的prefix是自定义枚举类型(组件或者业务)
 *   4. registerPrefix(IDPrefix prefix, const std::string& prefixStr)： 注册的自定义前缀，注册需要生成TraceID的组件或者业务
 *   5. parseID(TraceID id, uint64_t& timestamp, uint16_t& instanceId, uint16_t& sequence)：TraceID解析
 *   1,5的核心算法都是通过位运算来实现的
 */

#pragma once

#ifndef GENERATOR_ID_H
#define GENERATOR_ID_H

#include <atomic>
#include <string>
#include <chrono>
#include <sstream>
#include <iomanip>
#include <thread>
#include <mutex>
#include <unordered_map>
#include <functional>
#include <cstdint>

// ID类型定义
using TraceID = uint64_t;

// ID前缀类型
enum class IDPrefix {
    RENDER_OBJECT = 0,
    MESH,
    MATERIAL,
    SHADER,
    TEXTURE,
    CAMERA,
    LIGHT,
    FRAME,
    EVENT,
    GEOMETRY,
    USER_DEFINED
};

class IDGenerator {
private:
    // 单例模式
    IDGenerator();
    ~IDGenerator() = default;

    // 禁止拷贝
    IDGenerator(const IDGenerator&) = delete;
    IDGenerator& operator=(const IDGenerator&) = delete;

    // 核心ID生成器
    class AtomicIDGenerator {
    private:
        std::atomic<uint64_t> counter;
        uint16_t instanceId;

    public:
        AtomicIDGenerator(uint16_t instanceId)
            : instanceId(instanceId), counter(0) {}

        // 生成TraceId
        TraceID generate() {
            uint64_t seq = counter.fetch_add(1, std::memory_order_relaxed);
            uint64_t timestamp = getTimestamp();

            // ID结构: 时间戳(42位) | 实例ID(10位) | 序列号(12位)
            return ((timestamp & 0x3FFFFFFFFFF) << 22) |
                   ((instanceId & 0x3FF) << 12) |
                   (seq & 0xFFF);
        }

    private:
        uint64_t getTimestamp() {
            auto now = std::chrono::steady_clock::now();
            auto duration = now.time_since_epoch();
            return std::chrono::duration_cast<std::chrono::milliseconds>(duration).count();
        }
    };

    // 线程局部存储的ID生成器
    static thread_local std::unique_ptr<AtomicIDGenerator> threadLocalGenerator;

    // 实例ID分配
    static std::atomic<uint16_t> nextInstanceId;
    uint16_t instanceId;

    // 前缀映射
    std::unordered_map<IDPrefix, std::string> prefixMap;
    std::mutex prefixMutex;

public:
    // 获取单例实例
    static IDGenerator& getInstance();

    // 生成原始ID
    TraceID generateRaw();

    // 生成带前缀的字符串ID
    std::string generateString(IDPrefix prefix = IDPrefix::RENDER_OBJECT);

    // 生成带自定义前缀的字符串ID (用于扩展非注册组件或者业务前缀的场景)
    std::string generateCustomString(const std::string& customPrefix);

    // 注册自定义前缀
    void registerPrefix(IDPrefix prefix, const std::string& prefixStr);

    // 从ID解析信息
    static void parseID(TraceID id, uint64_t& timestamp, uint16_t& instanceId, uint16_t& sequence);

    // 获取ID生成统计信息
    struct Statistics {
        uint64_t totalGenerated;
        uint64_t perSecondRate;
        uint64_t lastResetTime;
    };

    Statistics getStatistics() const;

    // 重置统计（主要用于测试）
    void resetStatistics();

private:
    // 统计信息
    mutable std::mutex statsMutex;
    uint64_t totalGenerated;
    uint64_t lastSecondCount;
    uint64_t lastResetTime;

    // 更新统计
    void updateStatistics();
};

// 便捷宏定义
#define TRACE_ID(idType) IDGenerator::getInstance().generateString(IDPrefix::idType)
#define RAW_TRACE_ID IDGenerator::getInstance().generateRaw()
#define CUSTOM_TRACE_ID(prefix) IDGenerator::getInstance().generateCustomString(prefix)

// RAII包装器，用于跟踪ID的生命周期
class TraceScope {
private:
    std::string traceId;
    std::string functionName;
    std::chrono::steady_clock::time_point startTime;

public:
    TraceScope(const std::string& funcName, IDPrefix prefix = IDPrefix::EVENT);
    ~TraceScope();

    const std::string& getTraceId() const { return traceId; }
    void addTag(const std::string& key, const std::string& value);
};

#endif //GENERATOR_ID_H